--假设给定的4个数组成的集合 定义函数f(x)为对集合中的元素进行所有的可能的四则混合运算所得到的值

local core = {
  calcuTimes = 0
}


local operators = {
  add = function(l, r)
    return l+r
  end,
  sub = function(l, r)
    return l-r
  end,
  mul = function(l, r)
    return l*r
  end,
  div = function(l, r)
    return l/r
  end,
  rsub = function(l, r)
    return r-l
  end,
  rdiv = function(l, r)
    return r/l
  end,
}

local operatorStrs = {
  add = function(l, r)
    if string.len(l) > 2 then
      l = '('..l..')'
    end
    if string.len(r) > 2 then
      r = '('..r..')'
    end
    return l..'+'..r
  end,
  sub = function(l, r)
    if string.len(l) > 2 then
      l = '('..l..')'
    end
    if string.len(r) > 2 then
      r = '('..r..')'
    end
    return l..'-'..r
  end,
  mul = function(l, r)
    if string.len(l) > 2 then
      l = '('..l..')'
    end
    if string.len(r) > 2 then
      r = '('..r..')'
    end
    return l..'*'..r
  end,
  div = function(l, r)
    if string.len(l) > 2 then
      l = '('..l..')'
    end
    if string.len(r) > 2 then
      r = '('..r..')'
    end
    return l..'/'..r
  end,
  rsub = function(l, r)
    if string.len(l) > 2 then
      l = '('..l..')'
    end
    if string.len(r) > 2 then
      r = '('..r..')'
    end
    return r..'-'..l
  end,
  rdiv = function(l, r)
    if string.len(l) > 2 then
      l = '('..l..')'
    end
    if string.len(r) > 2 then
      r = '('..r..')'
    end
    return r..'/'..l
  end,
}

local function _calcu(set, out)
  if #set < 2 then
    if set[1].n == 24 then
      table.insert(out, set[1].s.."=24")
    end
    return
  end
  
  for i = 1, #set do
    for j = i + 1, #set do
      local a = set[i]
      local b = set[j]
      for k, op in pairs(operators) do
        local r = op(a.n, b.n)
        local opStr = operatorStrs[k]
        local rStr = opStr(a.s, b.s)
        core.calcuTimes = core.calcuTimes + 1
        
        --  通过这个结果和剩下的内容一起组合成一个新的集合
        local newSet = {{s=rStr, n=r}}
        for n = 1, #set do
          if n ~= i and n ~= j then
            table.insert(newSet, {s = set[n].s, n = set[n].n})
          end
        end
        
        _calcu(newSet, out)        
      end
      
    end
  end  
  
  return nil
end

function core.calculate(set)
  local out = {}
  
  local buildSet = {}
  for k, v in pairs(set) do
    buildSet[k] = { n = v, s = tostring(v) }
  end
  
  _calcu(buildSet, out)
  --dp(out)
  local calcuTimes = core.calcuTimes
  core.calcuTimes = 0
  return out,calcuTimes
end

local function _isVaild(set)
  if #set < 2 then    
    return set[1] == 24
  end
  
  for i = 1, #set do
    for j = i + 1, #set do
      for k, op in pairs(operators) do
        local newSet = {op(set[i], set[j])}
        for n = 1, #set do
          if n ~= i and n ~= j then
            table.insert(newSet, set[n])
          end
        end
        
        if _isVaild(newSet) then
          return true
        end        
      end
    end
  end  
  
  return false
end

function core.isVaild(set)
  return _isVaild(set)
end


return core